﻿using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using NthDownload.Agent;
using NthDownload.BL;
using NthDownload.Common.Collections;
using NthDownload.Common.Plugins;
using NthDownload.Common.ViewModels;
using NthDownload.Composition;
using NthDownload.Contracts;
using NthDownload.Contracts.Plugins.Downloads;
using NthDownload.Common.Utils;

namespace NthDownload.ViewModels
{
    public class QueueViewModel : ViewModelScreenBase
    {
        #region Class Members

        private NthQueue _queue;
        private AutoRefreshCollectionViewSource _downloadsViewSource;
        private IList _selectedDownloads;
        private double _vereticalOffset;
        private double _horizontalOffset;
        private DownloadViews _selectedView;

        #endregion Class Members

        #region Constructors

        public QueueViewModel(NthQueue queue)
        {
            //
            // Set defaults
            //
            DownloadsViewSource = new AutoRefreshCollectionViewSource();
            Queue = queue;
            SelectedDownloads = null;
            SelectedView = DownloadViews.Active;
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// The managed queue, this is a wrapper for the DownloadQueue
        /// </summary>
        public NthQueue Queue
        {
            get
            {
                return _queue;
            }
            set
            {
                _queue = value;
                NotifyOfPropertyChange(() => Queue);
                UpdateSelectedView();
            }
        }

        /// <summary>
        /// The currently selected downloads
        /// </summary>
        public IList SelectedDownloads
        {
            get
            {
                return _selectedDownloads;
            }
            set
            {
                _selectedDownloads = value;
                NotifyOfPropertyChange(() => SelectedDownloads);
            }
        }

        /// <summary>
        /// The currently selected view
        /// </summary>
        public DownloadViews SelectedView
        {
            get
            {
                return _selectedView;
            }
            set
            {
                _selectedView = value;
                UpdateSelectedView();
            }
        }

        /// <summary>
        /// The downloads view source
        /// </summary>
        public AutoRefreshCollectionViewSource DownloadsViewSource
        {
            get
            {
                return _downloadsViewSource;
            }
            set
            {
                _downloadsViewSource = value;
                NotifyOfPropertyChange(() => DownloadsViewSource);
            }
        }

        /// <summary>
        /// The vertical offset of the queue list
        /// </summary>
        public double VerticalOffset
        {
            get
            {
                return _vereticalOffset;
            }
            set
            {
                _vereticalOffset = value;
                NotifyOfPropertyChange(() => VerticalOffset);
            }
        }

        /// <summary>
        /// The horizontal offset of the queue list
        /// </summary>
        public double HorizontalOffset
        {
            get
            {
                return _horizontalOffset;
            }
            set
            {
                _horizontalOffset = value;
                NotifyOfPropertyChange(() => HorizontalOffset);
            }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Adds new downloads.
        /// </summary>
        public void AddDownloads()
        {
            //
            // Show download plugin selector
            //
            DownloadPluginSelectorViewModel downloadPluginSelectorViewModel = new DownloadPluginSelectorViewModel();
            if (NavigationService.ShowDialog(downloadPluginSelectorViewModel, false) != ViewModelResults.Select || downloadPluginSelectorViewModel.SelectedPlugin == null)
            {
                return;
            }

            //
            // Get download UI service
            //
            IDownloadUIService downloadUIService;
            if (!ImportService.TryGetExportValue(DownloadPluginContractNameService.CreateDownloadUIServiceContractName(downloadPluginSelectorViewModel.SelectedPlugin.GUID), out downloadUIService))
            {
                MessageDialogViewModel.ShowError("Couldn't load the UI Service from the " + downloadPluginSelectorViewModel.SelectedPlugin.DisplayName + " plugin.");
                return;
            }

            //
            // Create downloads
            //
            Task<List<IDownload>> createTask = downloadUIService.ShowAddDownloads();

            Task continueTask = createTask.ContinueWith(t =>
            {
                if (t.Exception == null)
                {
                    if (t.Result.Count > 0)
                    {
                        Task<QueueOperation> startTask;
                        Task<QueueOperation> addTask = Queue.AddDownloads(t.Result, out startTask);
                        addTask.Wait();

                        if (startTask != null)
                        {
                            startTask.Wait();
                        }
                    }
                }
                else
                {
                    throw t.Exception;
                }
            });

            TaskScheduler ts = TaskScheduler.FromCurrentSynchronizationContext();
            continueTask.ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    MessageDialogViewModel.ShowError(ExceptionUtils.GetInnerMostException(t.Exception).Message);
                }
            }, ts);
        }

        /// <summary>
        /// Starts downloads, if the downloads are in archived or inactive downloads they are removed and
        /// added to active downloads then started.
        /// </summary>
        public void StartDownloads(IDownload download)
        {
            Task<QueueOperation> startTask;

            //
            // If the item is selected then start all selected items otherwise only start the passed item
            //
            if (SelectedDownloads != null && SelectedDownloads.Contains(download))
            {
                startTask = Queue.StartDownloads(SelectedDownloads.OfType<IDownload>());
            }
            else
            {
                startTask = Queue.StartDownloads(new List<IDownload>() { download });
            }

            TaskScheduler ts = TaskScheduler.FromCurrentSynchronizationContext();
            startTask.ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    MessageDialogViewModel.ShowError(ExceptionUtils.GetInnerMostException(t.Exception).Message);
                }
            }, ts);
        }

        /// <summary>
        /// Pause downloads
        /// </summary>
        public void PauseDownloads(IDownload download)
        {
            Task<QueueOperation> pauseTask;

            //
            // If the item is selected then pause all selected items otherwise only pause the passed item
            //
            if (SelectedDownloads != null && SelectedDownloads.Contains(download))
            {
                pauseTask = Queue.PauseDownloads(SelectedDownloads.OfType<IDownload>());
            }
            else
            {
                pauseTask = Queue.PauseDownloads(new List<IDownload>() { download });
            }

            TaskScheduler ts = TaskScheduler.FromCurrentSynchronizationContext();
            pauseTask.ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    MessageDialogViewModel.ShowError(ExceptionUtils.GetInnerMostException(t.Exception).Message);
                }
            }, ts);
        }

        /// <summary>
        /// Stop downloads
        /// </summary>
        public void StopDownloads(IDownload download)
        {
            Task<QueueOperation> stopTask;

            //
            // If the item is selected then stop all selected items otherwise only stop the passed item
            //
            if (SelectedDownloads != null && SelectedDownloads.Contains(download))
            {
                stopTask = Queue.StopDownloads(SelectedDownloads.OfType<IDownload>());
            }
            else
            {
                stopTask = Queue.StopDownloads(new List<IDownload>() { download });
            }

            TaskScheduler ts = TaskScheduler.FromCurrentSynchronizationContext();
            stopTask.ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    MessageDialogViewModel.ShowError(ExceptionUtils.GetInnerMostException(t.Exception).Message);
                }
            }, ts);
        }

        /// <summary>
        /// Removes downloads
        /// </summary>
        public void RemoveDownloads(IDownload download)
        {
            Task<QueueOperation> removeTask;

            //
            // If the item is selected then remove all selected items otherwise only remove the passed item
            //
            if (SelectedDownloads != null && SelectedDownloads.Contains(download))
            {
                removeTask = Queue.RemoveDownloads(SelectedDownloads.OfType<IDownload>());
            }
            else
            {
                removeTask = Queue.RemoveDownloads(new List<IDownload>() { download });
            }

            TaskScheduler ts = TaskScheduler.FromCurrentSynchronizationContext();
            removeTask.ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    MessageDialogViewModel.ShowError(ExceptionUtils.GetInnerMostException(t.Exception).Message);
                }
            }, ts);
        }
        
        /// <summary>
        /// Move downloads up
        /// </summary>
        public void MoveUpDownloads(IDownload download)
        {
            Task<QueueOperation> moveTask;

            //
            // If the item is selected then move all selected items up otherwise only move the passed item up
            //
            if (SelectedDownloads != null && SelectedDownloads.Contains(download))
            {
                moveTask = Queue.MoveDownloadsUp(SelectedDownloads.OfType<IDownload>());
            }
            else
            {
                moveTask = Queue.MoveDownloadsUp(new List<IDownload>() { download });
            }

            TaskScheduler ts = TaskScheduler.FromCurrentSynchronizationContext();
            moveTask.ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    MessageDialogViewModel.ShowError(ExceptionUtils.GetInnerMostException(t.Exception).Message);
                }
            }, ts);
        }

        /// <summary>
        /// Moves the selected downloads down
        /// </summary>
        public void MoveDownDownloads(IDownload download)
        {
            Task<QueueOperation> moveTask;

            //
            // If the item is selected then move all selected items down otherwise only move the passed item down
            //
            if (SelectedDownloads != null && SelectedDownloads.Contains(download))
            {
                moveTask = Queue.MoveDownloadsDown(SelectedDownloads.OfType<IDownload>());
            }
            else
            {
                moveTask = Queue.MoveDownloadsDown(new List<IDownload>() { download });
            }

            TaskScheduler ts = TaskScheduler.FromCurrentSynchronizationContext();
            moveTask.ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    MessageDialogViewModel.ShowError(ExceptionUtils.GetInnerMostException(t.Exception).Message);
                }
            }, ts);
        }

        /// <summary>
        /// Displays all active downloads
        /// </summary>
        public void DisplayActiveDownloads()
        {
            SelectedView = DownloadViews.Active;
        }

        /// <summary>
        /// Displays all inactive downloads
        /// </summary>
        public void DisplayInactiveDownloads()
        {
            SelectedView = DownloadViews.Inactive;
        }

        /// <summary>
        /// Displays all archived downloads
        /// </summary>
        public void DisplayArchivedDownloads()
        {
            SelectedView = DownloadViews.Archived;
        }

        #endregion Methods

        #region Private Methods

        /// <summary>
        /// Updates the currently selected view from the value of the SelectedView property
        /// </summary>
        private void UpdateSelectedView()
        {
            switch (SelectedView)
            {
                case DownloadViews.Active:
                    LoadActiveDownloads();
                    break;
                case DownloadViews.Archived:
                    LoadArchivedDownloads();
                    break;
                case DownloadViews.Inactive:
                    LoadInactiveDownloads();
                    break;
                case DownloadViews.Search:
                    //TODO implement search
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// Loads the downlaods collection view source with all active downloads
        /// </summary>
        private void LoadActiveDownloads()
        {
            DownloadsViewSource.Source = null;

            DownloadsViewSource.SortDescriptions.Clear();
            DownloadsViewSource.SortDescriptions.Add(new SortDescription("Position", ListSortDirection.Ascending));

            DownloadsViewSource.Source = Queue.ActiveDownloads;
        }

        /// <summary>
        /// Loads the downlaods collection view source with all inactive downloads
        /// </summary>
        private void LoadInactiveDownloads()
        {
            DownloadsViewSource.Source = null;

            DownloadsViewSource.SortDescriptions.Clear();
            DownloadsViewSource.SortDescriptions.Add(new SortDescription("DateCreated", ListSortDirection.Ascending));

            DownloadsViewSource.Source = Queue.InactiveDownloads;
        }

        /// <summary>
        /// Loads the downlaods collection view source with all archived downloads
        /// </summary>
        private void LoadArchivedDownloads()
        {
            DownloadsViewSource.Source = null;

            DownloadsViewSource.SortDescriptions.Clear();
            DownloadsViewSource.SortDescriptions.Add(new SortDescription("DateCompleted", ListSortDirection.Ascending));

            DownloadsViewSource.Source = Queue.ArchivedDownloads;
        }

        #endregion Private Methods
    }
}
